package org.jeecg.modules.ncmeapis.network.service.impl;

import com.baomidou.mybatisplus.extension.toolkit.Db;
import org.jeecg.modules.ncmeapis.network.entities.entity.GroupPathPerm;
import org.jeecg.modules.ncmeapis.network.entities.entity.NetworkPath;
import org.jeecg.modules.ncmeapis.network.entities.entity.UserPathPerm;
import org.jeecg.modules.ncmeapis.network.entities.entity.dto.PathPermDTO;
import org.jeecg.modules.ncmeapis.network.entities.entity.vo.PathWithPerm;
import org.jeecg.modules.ncmeapis.network.config.NetworkErrorMsg;
import org.jeecg.modules.ncmeapis.network.service.IdentityService;
import org.jeecg.modules.ncmeapis.network.service.INetworkPathService;
import org.jeecg.modules.ncmeapis.network.service.INetworkPermissionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class NetworkPermissionServiceImpl implements INetworkPermissionService {

    @Autowired
    private IdentityService identityService;
    @Autowired
    private INetworkPathService networkPathService;

    @Override
    public NetworkPath checkPathExist(String pathId, String msg) {
        NetworkPath networkPath = networkPathService.getById(pathId);
        //校验文件或文件夹是否存在
        if (networkPath == null) throw new RuntimeException(msg);
        else return networkPath;
    }

    public NetworkPath checkPathExist(String pathId) {
        return checkPathExist(pathId, NetworkErrorMsg.PATH_NOT_EXIST);
    }

    @Override
    public void checkPathType(NetworkPath networkPath, String pathType, String msg) {
        if (!networkPath.getType().equals(pathType)) throw new RuntimeException(msg);
    }

    @Override
    public void checkPathType(NetworkPath networkPath, String pathType) {
        checkPathType(networkPath, pathType, NetworkErrorMsg.PATH_TYPE_ERROR);
    }

    public List<PathWithPerm> getPathsWithPermsByUserId(List<NetworkPath> paths, String userId) {
        //判断用户存在
        identityService.userExist(userId);
        if (paths == null || paths.isEmpty()) return new ArrayList<>();
        //先分别获取用户和用户组的目录权限,做成Map字典
        List<PathPermDTO> pathPermDTOS = Db.lambdaQuery(UserPathPerm.class).eq(UserPathPerm::getUserId, userId).list().stream().map(PathPermDTO::new).collect(Collectors.toList());
        List<String> groupIds = identityService.getGroupIdsByUserId(userId);
        if (!groupIds.isEmpty()) {
            pathPermDTOS.addAll(Db.lambdaQuery(GroupPathPerm.class).in(GroupPathPerm::getGroupId, groupIds).list().stream().map(PathPermDTO::new).collect(Collectors.toList()));
        }
        //合并字典
        Map<String, PathPermDTO> pathPermMap = pathPermDTOS.stream().collect(Collectors.toMap(PathPermDTO::getPathId, Function.identity(), new BinaryOperator<PathPermDTO>() {
            @Override
            public PathPermDTO apply(PathPermDTO pathPermDTO, PathPermDTO pathPermDTO2) {
                if (pathPermDTO.getPriority() > pathPermDTO2.getPriority()) return pathPermDTO;
                else if (pathPermDTO.getPriority() < pathPermDTO2.getPriority()) return pathPermDTO2;
                else return PathPermDTO.merge(pathPermDTO, pathPermDTO2);
            }
        }));
        //将目录转换为带权限的目录
        return paths.stream().map(networkPath -> {
            PathPermDTO lastPathPermDTO = getLastPathPermDTO(networkPath, pathPermMap);
            if (lastPathPermDTO == null) return null;
            return new PathWithPerm(networkPath, lastPathPermDTO);
        }).filter(Objects::nonNull).collect(Collectors.toList());
    }

    @Override
    public List<NetworkPath> checkPathsHasPerm(List<NetworkPath> paths, String userId, String... pathPermCode) {
        //获取用户分配了权限的目录（包括从父级目录继承下来的权限）
        List<PathWithPerm> pathWithPerms = getPathsWithPermsByUserId(paths, userId);
        if (pathWithPerms.isEmpty()) return paths;
        //筛选出没有权限的目录ids
        pathWithPerms.removeIf(pathWithPerm -> pathWithPerm.has(pathPermCode));
        List<String> lackPathIds = pathWithPerms.stream().map(PathWithPerm::getId).collect(Collectors.toList());
        //返回没有权限的目录
        return paths.stream().filter(networkPath -> lackPathIds.contains(networkPath.getId())).collect(Collectors.toList());
    }

    @Override
    public List<NetworkPath> checkThisAndChildrenHasPerm(NetworkPath path, String userId, String... pathPermCode) {
        //先获取当前目录的权限
        List<NetworkPath> thisPath = Collections.singletonList(path);
        List<PathWithPerm> thisPerms = getPathsWithPermsByUserId(thisPath, userId);
        //如果当前目录都没有权限,就不用检查下面的了,直接返回当前目录
        if (thisPerms.isEmpty() || thisPerms.get(0).lacks(pathPermCode))
            return thisPath;
        else {
            //如果当前目录有权限,获取指定目录下的所有文件和文件夹
            List<NetworkPath> allChildren = Db.lambdaQuery(NetworkPath.class).likeRight(NetworkPath::getPath, path.getPath() + "/").list();
            return checkPathsHasPerm(allChildren, userId, pathPermCode);
        }
    }

    /**
     * 获取最近的目录权限,从当前目录向上搜索,到根节点停止,若还没有则返回 null
     */
    private PathPermDTO getLastPathPermDTO(NetworkPath networkPath, Map<String, PathPermDTO> pathPermMap) {
        PathPermDTO pathPermDTO = pathPermMap.get(networkPath.getId());
        //如果直接就有该目录的权限，直接返回
        if (pathPermDTO != null) return pathPermDTO;
        else {
            String pid = networkPath.getPid();
            //如果pid是0,说明没有任何权限
            if (pid.equals(INetworkPathService.ROOT_PID_VALUE)) return null;
            //如果父目录有权限，赋予父级权限
            if (pathPermMap.containsKey(pid)) {
                return pathPermMap.get(pid);
            } else {
                //递归获取父目录的父目录的权限
                NetworkPath parentPath = Db.lambdaQuery(NetworkPath.class).eq(NetworkPath::getId, pid).one();
                return getLastPathPermDTO(parentPath, pathPermMap);
            }
        }
    }

}
